package com.miaoa.jbox2d.demo;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.util.AttributeSet;
import android.view.View;

import androidx.annotation.Nullable;

import org.jbox2d.callbacks.ContactImpulse;
import org.jbox2d.callbacks.ContactListener;
import org.jbox2d.collision.Manifold;
import org.jbox2d.dynamics.contacts.Contact;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * 碰撞view
 *
 * @Author Mlethe
 * @Date 2023/7/13
 */
public class JBox2DView extends View implements SensorEventListener {

    private final JBox2DImpl mJBox2DImpl = new JBox2DImpl();

    /**
     * 存钱罐图片资源id-前面
     */
    private int mBgForeResId = R.mipmap.bg_save_money_jar_fore;

    /**
     * 是否被销毁
     */
    private boolean isDestroyed = false;

    /**
     * 是否被移除
     */
    private boolean isRemoved = false;

    /**
     * 图片与view的比例
     */
    private float mRatio = 0.9f;

    /**
     * 文字画笔
     */
    private final Paint mPaint = new Paint();

    /**
     * Bitmap 数组
     */
    private final Map<Integer, Bitmap> mBitmapMap = new HashMap<>();

    /**
     * bitmap 旋转
     */
    private final Matrix mMatrix = new Matrix();

    /**
     * 文字顶部距离
     */
    private final float mTextTop;

    /**
     * 文字大小
     */
    private float mTextSize;

    /**
     * 文字前缀
     */
    private String mPrefix;

    /**
     * 计划总金额
     */
    private double mPlanMoney;

    /**
     * 已存入总金额
     */
    private double mMoney;

    /**
     * 已存入总金额是否已设置
     */
    private boolean isSettingMoney;

    /**
     * 是否为没有动画模式
     */
    private boolean isNoAnimator;

    /**
     * 存钱罐图片-前面、后面、盖子
     */
    private Bitmap mBgFore, mBgBack, mBgCover;

    /**
     * 存钱罐图片宽度、高度
     */
    private int mForeWidth, mForeHeight;

    /**
     * 存钱罐盖子位移距离
     */
    private final int mCoverTranslate;

    /**
     * 存钱罐盖子左边偏移量
     */
    private final int mCoverOffsetLeft;

    /**
     * 存钱罐盖子高度
     */
    private final int mCoverHeight;

    /**
     * 存钱计划icon
     */
    private Bitmap mIconBitmap;

    /**
     * bitmap的宽度与真实图片的宽度的比例
     */
    private float mIconRatio = 1f;

    /**
     * 存钱计划icon顶部偏移量
     */
    private final int mIconOffsetTop;

    /**
     * 存钱计划icon左边偏移量
     */
    private final int mIconOffsetLeft;

    /**
     * 存钱计划icon旋转角度
     */
    private final int mIconOffsetAngle = -19;

    /**
     * 重力传感器管理类
     */
    private SensorManager sensorManager;

    /**
     * 是否开始绘制
     */
    private boolean isStartDraw = true;

    /**
     * 翻盖旋转角度
     */
    private float mCoverChangeAngle = 0;

    /**
     * 翻盖顶部、左边位移距离
     */
    private float mCoverChangeTop = 0, mCoverChangeLeft = 0;

    /**
     * 是否开始关闭翻盖动画
     */
    private boolean isStartCloseCoverAnimator = false;

    /**
     * 是否开始翻盖动画
     */
    private boolean isStartCoverAnimator = false;

    /**
     * 变化监听
     */
    private OnChangeListener mOnChangeListener;

    /**
     * 等待添加的金额
     */
    private double mWaitAddMoney = 0.0;

    /**
     * 等待删除的金额
     */
    private double mWaitRemoveMoney = 0.0;

    /**
     * 等待添加的对象
     */
    private final ArrayList<RigidBody> mWaitAddList = new ArrayList<>();

    /**
     * 添加到世界
     */
    private final Runnable mRunnable = new Runnable() {
        @Override
        public void run() {
            if (isDestroyed) return;
            if (mWaitAddList.isEmpty()) {
                isStartCloseCoverAnimator = true;
                coverAnimator(-mCoverTranslate * mRatio, 0f, new AnimatorListenerAdapter() {
                    @Override
                    public void onAnimationEnd(Animator animation) {
                        super.onAnimationEnd(animation);
                        if (mOnChangeListener != null) {
                            mOnChangeListener.onAnimatorEnd();
                        }
                        isStartCloseCoverAnimator = false;
                        isStartCoverAnimator = false;
                        if (isDestroyed) return;
                        if (mWaitAddMoney <= 0.0) {
                            removeWaitMoney();
                        } else {
                            addWaitMoney();
                        }
                    }
                });
                return;
            }
            try {
                RigidBody rigidBody = mWaitAddList.remove(0);
                mJBox2DImpl.createBody(rigidBody, mCoverHeight * mRatio + getPaddingTop());
            } catch (Throwable t) {
                t.printStackTrace();
            }
            postDelayed(this, 100L);
        }
    };

    /**
     * 碰撞监听
     */
    private final ContactListener mContactListener = new ContactListener() {
        /**
         * 接触的 时候调用
         */
        @Override
        public void beginContact(Contact contact) {
        }

        /**
         * 碰撞结束
         */
        @Override
        public void endContact(Contact contact) {
        }

        /**
         * 这在联系人更新后调用。 这允许您在接触求解器之前检查接触
         * @param contact
         * @param manifold
         */
        @Override
        public void preSolve(Contact contact, Manifold manifold) {
        }

        /**
         * 这使您可以在求解器完成后检查接触。 这对于检查脉冲很有用
         * @param contact
         * @param contactImpulse
         */
        @Override
        public void postSolve(Contact contact, ContactImpulse contactImpulse) {
        }
    };

    public JBox2DView(Context context) {
        this(context, null);
    }

    public JBox2DView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public JBox2DView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        this(context, attrs, defStyleAttr, 0);
    }

    public JBox2DView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        mJBox2DImpl.setDensity(getResources().getDisplayMetrics().density);
        mCoverTranslate = JBox2DImpl.dp2px(context, 60f);
        mCoverOffsetLeft = JBox2DImpl.dp2px(context, 5.4f);
        mCoverHeight = JBox2DImpl.dp2px(context, 60f);
        mTextTop = JBox2DImpl.dp2px(context, 33f);
        mIconOffsetTop = JBox2DImpl.dp2px(context, 76f);
        mIconOffsetLeft = JBox2DImpl.dp2px(context, 11f);
        mTextSize = JBox2DImpl.sp2px(context, 15f);
        int textColor = Color.BLACK;
        if (attrs != null) {
            TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.JBox2DView);
            mRatio = a.getFloat(R.styleable.JBox2DView_viewRatio, mRatio);
            mTextSize = a.getDimensionPixelSize(R.styleable.JBox2DView_android_textSize, (int) mTextSize);
            textColor = a.getColor(R.styleable.JBox2DView_android_textColor, textColor);
            a.recycle();
        }
        mPaint.setAntiAlias(true);
        mPaint.setStrokeWidth(2);
        mPaint.setTextSize(mTextSize);
        mPaint.setFakeBoldText(true);
        mPaint.setColor(textColor);
    }

    /**
     * 添加图片
     */
    private void setBitmaps() {
        if (!mBitmapMap.isEmpty()) return;
        mBitmapMap.put(1, BitmapFactory.decodeResource(getResources(), R.mipmap.ic_save_money_gold_1));
        mBitmapMap.put(2, BitmapFactory.decodeResource(getResources(), R.mipmap.ic_save_money_gold_2));
        mBitmapMap.put(3, BitmapFactory.decodeResource(getResources(), R.mipmap.ic_save_money_gold_3));
        mBitmapMap.put(4, BitmapFactory.decodeResource(getResources(), R.mipmap.ic_save_money_gold_4));
        mBitmapMap.put(5, BitmapFactory.decodeResource(getResources(), R.mipmap.ic_save_money_gold_5));
        mBitmapMap.put(6, BitmapFactory.decodeResource(getResources(), R.mipmap.ic_save_money_gold_6));
        mBitmapMap.put(7, BitmapFactory.decodeResource(getResources(), R.mipmap.ic_save_money_gold_7));
        mBitmapMap.put(8, BitmapFactory.decodeResource(getResources(), R.mipmap.ic_save_money_gold_8));
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        createWorld(right - left);
    }

    /**
     * 存钱罐图片资源id-前面
     *
     * @param resId 资源id
     * @return
     */
    public JBox2DView setBgForeResId(int resId) {
        mBgForeResId = resId;
        return this;
    }

    /**
     * 创建世界
     *
     * @param width view宽度
     */
    public JBox2DView createWorld(int width) {
        mJBox2DImpl.createWorld(getContext(), mForeWidth * mRatio, mForeHeight * mRatio, (width - mForeWidth * mRatio) / 2f, getPaddingTop(), mRatio);
        mJBox2DImpl.setContactListener(mContactListener);
        return this;
    }

    /**
     * 变化监听
     *
     * @param listener
     */
    public JBox2DView setOnChangeListener(OnChangeListener listener) {
        this.mOnChangeListener = listener;
        return this;
    }

    /**
     * 设置前缀
     *
     * @param prefix 前缀
     */
    public JBox2DView setPrefix(String prefix) {
        this.mPrefix = prefix;
        return this;
    }

    /**
     * 设置计划总金额
     *
     * @param money 金额
     */
    public JBox2DView setPlanMoney(double money) {
        if (isDestroyed || money < 0.0) return this;
        this.mPlanMoney = money;
        return this;
    }

    /**
     * 设置金额计算金币数量
     *
     * @param money 金额
     */
    public JBox2DView setMoney(double money) {
        post(() -> {
            if (isDestroyed || money <= 0.0) return;
            if (isSettingMoney || isStartCloseCoverAnimator) return;
            isSettingMoney = true;
            mMoney = money;
            changeGoldType((int) Math.ceil(mMoney), 1, true);
            if (isStartCoverAnimator) return;
            isStartCoverAnimator = true;
            if (mOnChangeListener != null) {
                mOnChangeListener.onAnimatorStart();
            }
            coverAnimator(0f, -mCoverTranslate * mRatio, new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    super.onAnimationEnd(animation);
                    if (isDestroyed) return;
                    post(mRunnable);
                }
            });
        });
        return this;
    }

    /**
     * 设置金额计算金币数量（没有动画）
     *
     * @param money 金额
     * @return
     */
    public synchronized JBox2DView setMoneyNoAnimator(double money) {
        if (isDestroyed || money <= 0.0) return this;
        if (isSettingMoney || isStartCloseCoverAnimator) return this;
        isSettingMoney = true;
        isNoAnimator = true;
        mMoney = money;
        changeGoldType((int) Math.ceil(mMoney), 1, true);
        for (RigidBody rigidBody : mWaitAddList) {
            mJBox2DImpl.createBody(rigidBody, mCoverHeight * mRatio + getPaddingTop());
        }
        mWaitAddList.clear();
        for (int i = 0; i < 60; i++) {
            mJBox2DImpl.startWorld();
            try {
                Thread.sleep(1L);
            } catch (Throwable t) {
                t.printStackTrace();
            }
        }
        return this;
    }

    /**
     * 添加金币
     * 计算方法：
     * 个位为 0 时，向前十位借 1 ，1 类型金币为 10 个，然后其他每一位递归用总数减去 10 后的值除以 10 之后的商取 10 的余数为对应类型金币的数量。
     * 个位不为 0 时，每一位递归用除以 10 之后的商取 10 的余数为对应类型金币的数量。
     *
     * @param money  金额
     * @param number 颜色类型编号
     * @param isAdd  是否是添加，true 为添加，false 为删除
     */
    private void changeGoldType(int money, int number, boolean isAdd) {
        int remainder = money % 10;
        if (remainder == 0 && number == 1) {
            if (isAdd) {
                addRigidBody(number, 10);
            } else {
                removeRigidBody(number, 10);
            }
            int discuss = (money - 10) / 10;
            if (discuss < 1) return;
            changeGoldType(discuss, number + 1, isAdd);
            return;
        }
        if (isAdd) {
            addRigidBody(number, remainder);
        } else {
            removeRigidBody(number, remainder);
        }
        int discuss = money / 10;
        if (discuss < 1) return;
        changeGoldType(discuss, number + 1, isAdd);
    }

    /**
     * 添加金额
     *
     * @param money 金额
     */
    public JBox2DView addMoney(double money) {
        post(() -> {
            if (isDestroyed || money <= 0.0) return;
            mWaitAddMoney += money;
            if (isStartCloseCoverAnimator) return;
            addWaitMoney();
        });
        return this;
    }

    /**
     * 添加当前金额
     *
     * @param money 金额
     */
    private synchronized void addCurrentMoney(double money) {
        if (isDestroyed) return;
        mMoney += money;
        changeGoldType((int) Math.ceil(money), 1, true);
        if (isStartCoverAnimator) return;
        isStartCoverAnimator = true;
        if (mOnChangeListener != null) {
            mOnChangeListener.onAnimatorStart();
        }
        coverAnimator(0f, -mCoverTranslate * mRatio, new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                if (isDestroyed) return;
                post(mRunnable);
            }
        });
    }

    /**
     * 添加等待添加的金额
     */
    private synchronized void addWaitMoney() {
        if (mWaitAddMoney <= 0.0) return;
        double addMoney = mWaitAddMoney;
        mWaitAddMoney = 0.0;
        addCurrentMoney(addMoney);
    }

    /**
     * 添加金币
     *
     * @param type  类型
     * @param count 数量
     */
    private void addRigidBody(int type, int count) {
        for (int i = 0; i < count; i++) {
            Bitmap bitmap = mBitmapMap.get(type);
            if (bitmap == null) continue;
            RigidBody rigidBody = new RigidBody(type, bitmap.getWidth(), bitmap.getHeight());
            mWaitAddList.add(rigidBody);
        }
    }

    /**
     * 移除金币
     *
     * @param type  类型
     * @param count 数量
     */
    private void removeRigidBody(int type, int count) {
        Iterator<RigidBody> iterator = mJBox2DImpl.getBodyList().iterator();
        int removeCount = 0;
        while (iterator.hasNext()) {
            RigidBody rigidBody = iterator.next();
            if (rigidBody.getType() == type) {
                iterator.remove();
                mJBox2DImpl.destroyBody(rigidBody);
                removeCount++;
            }
            if (removeCount >= count) return;
        }
    }

    /**
     * 重置
     */
    public void reset() {
        if (isDestroyed) return;
        removeCallbacks(mRunnable);
        mPlanMoney = 0.0;
        isSettingMoney = false;
        isStartCloseCoverAnimator = false;
        mMoney = 0.0;
        mCoverChangeTop = 0f;
        mCoverChangeLeft = 0;
        mCoverChangeAngle = 0;
        mWaitAddMoney = 0.0;
        mWaitAddList.clear();
        mWaitRemoveMoney = 0.0;
        isStartCoverAnimator = false;
        mJBox2DImpl.removeAllBody();
    }

    /**
     * 移除部分金额
     */
    public void removeMoney(double money) {
        if (isDestroyed || mMoney <= 0.0 || money <= 0.0) return;
        mWaitRemoveMoney += money;
        if (isStartCoverAnimator) return;
        removeWaitMoney();
    }

    /**
     * 移除删除金额
     */
    private synchronized void removeWaitMoney() {
        if (mWaitRemoveMoney <= 0.0) return;
        double money = mWaitRemoveMoney;
        mWaitRemoveMoney = 0.0;
        mMoney -= money;
        if (mMoney <= 0.0) {
            mMoney = 0.0;
            mJBox2DImpl.removeAllBody();
            return;
        }
        changeGoldType((int) Math.ceil(money), 1, false);
    }

    /**
     * 设置存钱计划icon
     *
     * @param bitmap bitmap
     */
    public JBox2DView setImageBitmap(Bitmap bitmap) {
        if (isDestroyed) return this;
        if (mIconBitmap != null && !mIconBitmap.isRecycled()) {
            try {
                mIconBitmap.recycle();
            } catch (Throwable t) {
                t.printStackTrace();
            }
        }
        this.mIconBitmap = bitmap;
        return this;
    }

    /**
     * 设置存钱计划icon
     *
     * @param drawable drawable
     */
    public JBox2DView setImageDrawable(Drawable drawable) {
        if (isDestroyed) return this;
        if (mIconBitmap != null && !mIconBitmap.isRecycled()) {
            try {
                mIconBitmap.recycle();
            } catch (Throwable t) {
                t.printStackTrace();
            }
        }
        if (drawable == null) {
            this.mIconBitmap = null;
            return this;
        }
        // 取 drawable 的长宽
        int w = drawable.getIntrinsicWidth();
        int h = drawable.getIntrinsicHeight();

        // 取 drawable 的颜色格式
        Bitmap.Config config = drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565;
        // 建立对应 bitmap
        Bitmap bitmap = Bitmap.createBitmap(w, h, config);
        // 建立对应 bitmap 的画布
        Canvas canvas = new Canvas(bitmap);
        drawable.setBounds(0, 0, w, h);
        // 把 drawable 内容画到画布中
        drawable.draw(canvas);
        this.mIconBitmap = bitmap;
        return this;
    }

    /**
     * 设置存钱计划icon
     *
     * @param resId 资源id
     */
    public JBox2DView setImageResource(int resId) {
        if (isDestroyed) return this;
        if (mIconBitmap != null && !mIconBitmap.isRecycled()) {
            try {
                mIconBitmap.recycle();
            } catch (Throwable t) {
                t.printStackTrace();
            }
        }
        try {
            this.mIconBitmap = BitmapFactory.decodeResource(getResources(), resId);
        } catch (Throwable t) {
            t.printStackTrace();
            this.mIconBitmap = null;
        }
        return this;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        if (heightMode == MeasureSpec.AT_MOST || heightMode == MeasureSpec.UNSPECIFIED) {
            heightMeasureSpec = MeasureSpec.makeMeasureSpec((int) (getPaddingTop() + mForeHeight * mRatio + getPaddingBottom()), MeasureSpec.EXACTLY);
        }
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (isDestroyed || isRemoved || !isStartDraw) return;
        int paddingTop = getPaddingTop();
        int width = getWidth();
        // 绘制罐子后面
        if (mBgBack != null && !mBgBack.isRecycled()) {
            int drawWidth = mBgBack.getWidth();
            float left = (width - drawWidth * mRatio) / 2f;
            float top = paddingTop;
            mMatrix.reset();
            mMatrix.setScale(mRatio, mRatio);
            mMatrix.postTranslate(left, top);
            canvas.drawBitmap(mBgBack, mMatrix, null);
        }
        // 绘制金币
        mJBox2DImpl.startWorld();
        for (RigidBody body : mJBox2DImpl.getBodyList()) {
            Bitmap bitmap = mBitmapMap.get(body.getType());
            if (bitmap == null || bitmap.isRecycled()) continue;
            float left = mJBox2DImpl.getBodyX(body);
            float top = mJBox2DImpl.getBodyY(body);
            mMatrix.reset();
            mMatrix.setScale(mRatio, mRatio);
            mMatrix.postTranslate(left, top);
            mMatrix.postRotate((float) mJBox2DImpl.getBodyAngle(body), left + body.getWidth() * mRatio / 2f, top + body.getHeight() * mRatio / 2f);
            canvas.drawBitmap(bitmap, mMatrix, null);
        }
        // 绘制罐子盖子
        if (mBgCover != null && !mBgCover.isRecycled()) {
            int drawWidth = mBgCover.getWidth();
            float left = (width - drawWidth * mRatio) / 2f + mCoverOffsetLeft * mRatio + mCoverChangeLeft;
            float top = paddingTop + mCoverChangeTop * mRatio;
            mMatrix.reset();
            mMatrix.setScale(mRatio, mRatio);
            mMatrix.postTranslate(left, top);
            mMatrix.postRotate(mCoverChangeAngle, left, top);
            canvas.drawBitmap(mBgCover, mMatrix, null);
        }
        // 绘制罐子前面
        float foreLeft = (width - mForeWidth * mRatio) / 2f;
        if (mBgFore != null && !mBgFore.isRecycled()) {
            float top = paddingTop;
            mMatrix.reset();
            mMatrix.setScale(mRatio, mRatio);
            mMatrix.postTranslate(foreLeft, top);
            canvas.drawBitmap(mBgFore, mMatrix, null);
        }
        // 绘制计划icon
        if (mIconBitmap != null && !mIconBitmap.isRecycled()) {
            int iconWidth = mIconBitmap.getWidth();
            int iconHeight = mIconBitmap.getHeight();
            float left = foreLeft + mIconOffsetLeft * mRatio;
            float top = paddingTop + mIconOffsetTop * mRatio;
            float ratio = mIconRatio * mRatio * 1.1f;
            mMatrix.reset();
            mMatrix.setScale(ratio, ratio);
            mMatrix.postTranslate(left, top);
            mMatrix.postRotate(mIconOffsetAngle, left + iconWidth * ratio / 2f, top + iconHeight * ratio / 2f);
            canvas.drawBitmap(mIconBitmap, mMatrix, null);
        }
        if (mPlanMoney > 0.0) {
            // 绘制文字
            mPaint.setTextSize(mTextSize * mRatio);
            String str = "";
            if (mPrefix != null && !mPrefix.isEmpty()) {
                str += mPrefix + " ";
            }
            str += String.format("%.2f", mPlanMoney);
            float textWidth = mPaint.measureText(str);
            canvas.drawText(str, (width - textWidth) / 2f, paddingTop + mTextTop * mRatio + getBaseLine(), mPaint);
        } else if (isNoAnimator) {
            // 绘制文字
            mPaint.setTextSize(mTextSize * mRatio);
            String str = "";
            if (mPrefix != null && !mPrefix.isEmpty()) {
                str += mPrefix + " ";
            }
            str += String.format("%.2f", mMoney);
            float textWidth = mPaint.measureText(str);
            canvas.drawText(str, (width - textWidth) / 2f, paddingTop + mTextTop * mRatio + getBaseLine(), mPaint);
        }
        // 绘制世界边框
        for (RectF rect : mJBox2DImpl.getRectList()) {
            canvas.drawLine(rect.left, rect.top, rect.right, rect.bottom, mPaint);
        }
        invalidate();
    }

    /**
     * 文字基线
     *
     * @return 基线位置
     */
    private float getBaseLine() {
        Paint.FontMetrics metrics = mPaint.getFontMetrics();
        return (metrics.bottom - metrics.top) / 2 - metrics.descent;
    }

    /**
     * 翻盖动画
     */
    private void coverAnimator(float start, float end, Animator.AnimatorListener listener) {
        ValueAnimator animator = ValueAnimator.ofFloat(start, end);
        animator.setDuration(1000L);
        animator.addUpdateListener(animation -> {
            mCoverChangeTop = (float) animation.getAnimatedValue();
            mCoverChangeLeft = mCoverChangeTop / 2;
            mCoverChangeAngle = mCoverChangeTop / 10;
        });
        animator.addListener(listener);
        animator.start();
    }

    /**
     * 初始化数据
     */
    public JBox2DView initDrawable() {
        Context context = getContext();
        if (context != null) {
            if (mBgFore == null) {
                mBgFore = BitmapFactory.decodeResource(getResources(), mBgForeResId);
                if (mBgFore != null) {
                    mForeWidth = mBgFore.getWidth();
                    mForeHeight = mBgFore.getHeight();
                    mIconRatio = mForeWidth / 1047f;
                }
            }
            if (mBgBack == null) {
                mBgBack = BitmapFactory.decodeResource(getResources(), R.mipmap.bg_save_money_jar_back);
            }
            if (mBgCover == null) {
                mBgCover = BitmapFactory.decodeResource(getResources(), R.mipmap.bg_save_money_jar_cover);
            }
            setBitmaps();
        }
        return this;
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        boolean isChanged = isRemoved;
        isRemoved = false;
        Context context = getContext();
        if (context != null) {
            sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
            Sensor defaultSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
            // 注册传感器监听
            sensorManager.registerListener(this, defaultSensor, SensorManager.SENSOR_DELAY_GAME);
        }
        initDrawable();
        if (isChanged) {
            addWaitMoney();
        }
    }

    /**
     * 释放资源
     */
    public void release() {
        if (mBgFore != null && !mBgFore.isRecycled()) {
            try {
                mBgFore.recycle();
            } catch (Throwable t) {
                t.printStackTrace();
            }
        }
        mBgFore = null;
        if (mBgBack != null && !mBgBack.isRecycled()) {
            try {
                mBgBack.recycle();
            } catch (Throwable t) {
                t.printStackTrace();
            }
        }
        mBgBack = null;
        if (mBgCover != null && !mBgCover.isRecycled()) {
            try {
                mBgCover.recycle();
            } catch (Throwable t) {
                t.printStackTrace();
            }
        }
        mBgCover = null;
        for (Map.Entry<Integer, Bitmap> entry : mBitmapMap.entrySet()) {
            try {
                Bitmap bitmap = entry.getValue();
                if (bitmap != null && !bitmap.isRecycled()) {
                    bitmap.recycle();
                }
            } catch (Throwable t) {
                t.printStackTrace();
            }
        }
        mBitmapMap.clear();
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        isRemoved = true;
        if (sensorManager != null) {
            // 取消传感器监听
            sensorManager.unregisterListener(this);
            sensorManager = null;
        }
        release();
    }

    @Override
    public void onSensorChanged(SensorEvent event) {
        if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
            if (!isStartDraw) return;
            float x = event.values[0] * 0.3f;
            float y = event.values[1] * 0.3f;
            mJBox2DImpl.applyLinearImpulse(-x, y);
        }
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {

    }

    /**
     * 恢复
     */
    public void resume() {
        isStartDraw = true;
        if (isDestroyed || isRemoved) return;
        invalidate();
    }

    /**
     * 暂停
     */
    public void stop() {
        isStartDraw = false;
    }

    /**
     * 销毁
     */
    public void destroy() {
        isDestroyed = true;
        isNoAnimator = false;
        if (mIconBitmap != null && !mIconBitmap.isRecycled()) {
            try {
                mIconBitmap.recycle();
            } catch (Throwable t) {
                t.printStackTrace();
            }
        }
        mIconBitmap = null;
        mMoney = 0.0;
        mWaitRemoveMoney = 0.0;
        mWaitAddMoney = 0.0;
        mWaitAddList.clear();
        mJBox2DImpl.destroy();
    }

    public interface OnChangeListener {
        /**
         * 动画开始
         */
        void onAnimatorStart();

        /**
         * 动画结束
         */
        void onAnimatorEnd();
    }
}